package com.yzi.core.collection
{
	import flash.utils.getQualifiedClassName;
	
	import mx.charts.chartClasses.InstanceCache;

	public class Collection implements ICollection
	{
		private var m_type:Class;
		private var m_itemList:Array;
		private var m_enableTypeChecking:Boolean;
		
		public function Collection($type:Class, $list:Array = null, $enableTypeChecking:Boolean = true)
		{
			m_type = $type;
			m_enableTypeChecking = $enableTypeChecking;
			if($list) m_itemList = $list;
			else m_itemList = new Array();
		}
		
		private function inspectVaildTypes($value:Array): void
		{
			if(m_enableTypeChecking == false) return;
			
			for each(var item:Object in $value)
			{
				if(!(item is m_type)) {
					throw new TypeError(getQualifiedClassName(item) + " is not a vaild " + getQualifiedClassName(m_type));
					
					return;
				}
			}
		}
		
		public function Clear():void { m_itemList.length = 0; }
		
		public function Size():int { return m_itemList.length; }
		
		public function AddItem($value:*): *
		{
			Concat($value);
			return $value;
		}
		
		public function AddItemAt($value:*, $index:int): *
		{
			Splice($index, 0, $value);
			return $value;
		}
		
		public function RemoveItem($value:*): *
		{
			var index:int = IndexOf($value, 0);
			RemoveItemAt(index);
			
			return null;
		}
		
		public function RemoveItemAt($index:int): * { return Splice($index, 1)[1]; }
		
		public function Push(...$args): uint
		{
			var oldValue:Array = m_itemList;
			inspectVaildTypes($args);
			
			for(var i:int = 0; i < $args.length; ++i)
			{
				m_itemList.push($args[i]);
			}
			
			return m_itemList.length;
		}
		
		public function Concat(...$args): Array
		{
			var oldValue:Array = m_itemList;
			inspectVaildTypes($args);
			
			m_itemList.concat($args);
			
			return m_itemList;
		}
		
		public function Shift(): *
		{
			var oldvalue:Array = m_itemList;
			var item:* = m_itemList.shift();
			
			return item;
		}
		
		public function Splice($startIndex:int, $deleteCount:uint, ... $values): Array
		{
			var result:Array;
			var oldValue:Array = m_itemList;
			
			inspectVaildTypes($values);
			
			if($values.length != 0) result = m_itemList.splice($startIndex - 1, $deleteCount, $values);
			else result = m_itemList.splice($startIndex - 1, $deleteCount);
			
			return result;
		}
		
		public function UnShift(... $args): uint
		{
			inspectVaildTypes($args);
			var oldValue:Array = m_itemList;
			
			for(var i:int = 0; i < $args.length; ++i) m_itemList.unshift($args[i]);
				
			return m_itemList.length;
		}
		
		public function Reverse(): Array
		{
			var result:Array = m_itemList;
			result.reverse();
			
			return result;
		}
		
		public function Every($callback:Function, $thisObject:* = null): Boolean { return m_itemList.every($callback,$thisObject); }
		
		public function Filter($callback:Function, $thisObject:* = null): Array { return m_itemList.filter($callback,$thisObject); }
		
		public function ForEach($callback:Function, $thisObject:* = null): void { m_itemList.forEach($callback, $thisObject); }
		
		public function IndexOf($searchElement:*, $fromIndex:int = 0): int { return m_itemList.indexOf($searchElement, $fromIndex); }
		
		public function Join($sep:*):String { return m_itemList.join($sep); }
		
		public function LastIndexOf($searchElement:*, $fromIndex:int = 0x7fffffff): int { return m_itemList.lastIndexOf($searchElement, $fromIndex); }
		
		public function Map($callback:Function, $thisObject:* = null): Array { return m_itemList.map($callback, $thisObject); }
		
		public function Slice($startIndex:int = 0, $endIndex:int = 16777215): Array{ return m_itemList.slice($startIndex, $endIndex); }
		
		public function Some($callback:Function, $thisObject:* = null): Boolean { return m_itemList.some($callback, $thisObject); }
		
		public function Sort(...$args): Array { return m_itemList.sort($args); }
		
		public function SortOn($fieldName:Object, $options:Object = null): Array{ return m_itemList.sortOn($fieldName, $options); }
		
		public function get enableTypeChecking(): Boolean { return m_enableTypeChecking; }
		
		public function set enableTypeChecking($value:Boolean): void { m_enableTypeChecking = $value; }
		
		public function get itemList(): Array { return m_itemList; }
		
		public function set itemList($value:Array): void
		{
			inspectVaildTypes($value);
			
			if($value != m_itemList) {
				var oldValue:Array = m_itemList;
				m_itemList = $value;
			}
		}
		
		public function GetItemAt($index:int): * { return m_itemList[$index]; }
		
		public function GetItemIndex($value:*): int { return IndexOf($value, 0); }
		
		public function SetItemIndex($value:*, $newIndex:Number): Boolean { return true; }
		
		public function IsContain($object:*):Boolean
		{
			var result:Boolean = false;
			var index:int = IndexOf($object);
			if(index > 0) result = true;

			return false;
		}
		
		public function IsEmpty():Boolean {	return (m_itemList.length == 0); }
		
		public function ToArray():Array	{ return m_itemList.concat(); }
	}
}

import com.yzi.core.collection.Collection;
import com.yzi.core.collection.IIterator;

internal class Iterator implements IIterator
{
	private var m_collection:Collection;
	private var m_list:Array;
	private var m_cursor:int;
	private var m_size:int;
	
	public function Iterator($collection:Collection)
	{
		m_collection = $collection;
		m_list = $collection.ToArray();
		m_cursor = 0;
		m_size = $collection.Size();
	}
	
	public function Start(): void
	{
		m_cursor = 0;
	}
	
	public function Next(): *
	{
		return m_list[m_cursor++];
	}
	
	public function HasNext(): Boolean
	{
		return m_cursor < m_size;
	}
	
	public function get data(): *
	{
		return m_list[m_cursor];
	}
	
	public function set data($object:*): void
	{
		m_collection.RemoveItemAt(m_cursor);
		m_collection.AddItemAt($object, m_cursor);
	}	
}